package org.example.collection;

import cn.hutool.core.lang.Console;
import org.junit.Test;

import java.util.*;

/**
 * Java jdk 原生  ArrayList 集合 API 测试
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2021/1/26 19:09
 */
@SuppressWarnings("all")
public class ArrayListTest {

    /**
     * ArrayList(Collection<? extends E> c)
     * list、Set 转 List
     */
    @Test
    public void set2List() {
        Set<String> set = new HashSet<>();
        set.add("法国");
        set.add("中国");
        set.add("美国");

        List<Object> list = new ArrayList<>(set);
        System.out.println(list);//[美国, 法国, 中国]
    }

    /**
     * removeAll(Collection<?> c)：从列表中移除所有包含在指定集合中的元素(可选操作)
     */
    @Test
    public void removeAll() {
        List<String> list = new ArrayList<>();
        list.add("10");
        list.add("20");
        list.add("30");
        list.add("20");
        list.add("40");

        List<String> list2 = new ArrayList<>();
        List<String> list3 = new ArrayList<>();

        list2.add("20");
        list2.add("402");
        list2.add("400");

        boolean removeAll1 = list.removeAll(list2);
        boolean removeAll2 = list.removeAll(list3);

        System.out.println(removeAll1);//true
        System.out.println(removeAll2);//false
        System.out.println(list);//[10, 30, 40]
        System.out.println(list2);//[20, 402, 400]
    }

    /**
     * T[] toArray(T[] a)：list 转数组
     * 1、【强制】使用集合转数组的方法，必须使用集合的toArray(T[] array)，传入的是类型完全一致、长度为0的空数组.
     * 2、反例：直接使用 toArray 无参方法存在问题，此方法返回值只能是 Object[] 类，若强转其它类型数组将出现 ClassCastException 错误。
     * 3、使用 toArray 带参方法，数组空间大小的 length：
     * * 1）等于 0，动态创建与 size 相同的数组，性能最好。
     * * 2）大于 0 但小于 size，重新创建大小等于 size 的数组，增加 GC 负担。
     * * 3）等于 size，在高并发情况下，数组创建完成之后，size 正在变大的情况下，负面影响与2相同。
     * * 4）大于 size，空间浪费，且在 size 处插入 null 值，存在 NPE 隐患。
     */
    @Test
    public void toArrayTest1() {
        List<String> list = new ArrayList<>(2);
        list.add("好汉");
        list.add("HuXiao");
        list.add("110");
        list.add("120");
        String[] array = list.toArray(new String[0]);

        // [好汉, HuXiao, 110, 120]
        Console.log(array);
    }

    /**
     * 1、{@link Arrays#asList(java.lang.Object[])} 返回的是 Arrays 的内部类 {@link Arrays.ArrayList}，而并不是 java.util.ArrayList
     * 2、内部类继承关系：private static class ArrayList<E> extends AbstractList<E> extends AbstractCollection<E> implements List<E>
     * 3、Arrays 的内部类 {@link ArrayList} 只重写了部分方法，而  add、remove 方法是没有重写的，在 AbstractList 中直接抛的异常 throw new UnsupportedOperationException();
     * 4、asList 返回的集合如果调用 add、remove 等方法，就会抛出异常 UnsupportedOperationException - 不支持的操作
     */
    @Test
    public void asListTest1() {
        String[] array1 = new String[]{"中国", "美国", "英国", "法国"};
        List<String> list1 = Arrays.asList(array1);

        String[] array2 = list1.toArray(new String[list1.size()]);
        System.out.println(list1);//[中国, 美国, 英国, 法国]
        System.out.println(Arrays.asList(array2));//[中国, 美国, 英国, 法国]
    }

    /**
     * boolean retainAll(Collection<?> c)：求与集合 c 的交集。
     * 1、即凡是集合 c 中的元素，全部保留；方式集合c中没有的元素，全部舍弃。
     * 2、自己的内容会发生改变，集合 c 的内容不改变。
     */
    @Test
    public void retainAll() {
        List<String> list = new ArrayList<>();
        list.add("10");
        list.add("20");
        list.add("30");

        List<String> list2 = new ArrayList<>();
        list2.add("50");
        list2.add("20");
        list2.add("40");

        boolean retainAll = list.retainAll(list2);
        System.out.println(retainAll);//true
        System.out.println(list);//[20]
        System.out.println(list2);//[50, 20, 40]
    }

    /**
     * ArrayList 的 subList 方法注意事项:
     * 修改原集合元素的值，会影响子集合
     * 修改子集合元素的值，会影响原集合
     * 修改原集合的结构，当再访问子集合时，会引起 ConcurrentModificationException 异常.
     * 修改子集合的结构，当再访问原集合时，会引起 ConcurrentModificationException 异常.
     */
    @Test
    public void testSubList() {
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map1 = new HashMap<>();
        Map<String, Object> map2 = new HashMap<>();
        map1.put("code", 200);
        map2.put("code", 500);
        list.add(map1);
        list.add(map2);

        List<Map<String, Object>> subList = list.subList(0, 1);
        System.out.println(subList);//[{code=200}]

        //修改原集合元素的值，会影响子集合
        list.get(0).put("msg", "success");
        System.out.println(subList);//[{msg=success, code=200}]

        //修改子集合元素的值，会影响原集合
        subList.get(0).put("data", null);
        System.out.println(list);//[{msg=success, code=200, data=null}, {code=500}]

        //修改原集合的结构，当再访问子集合时，会引起 ConcurrentModificationException 异常.
        //修改子集合的结构，当再访问原集合时，会引起 ConcurrentModificationException 异常.
        list.add(map1);
        System.out.println(subList);
    }


}
